<?php
/**
 * Created by PhpStorm.
 * User: jjj
 * Date: 2017/12/15
 * Time: 10:34
 */

namespace app\common\model;


use app\api\model\user\Users;
use app\common\task\ICreditTask;
use app\common\task\impl\AttendanceTask;
use app\common\task\impl\DefaultDailyTimesTask;
use app\common\task\impl\DefaultOnceTask;
use app\common\task\impl\DefaultRebateTask;
use app\common\task\impl\InfiniteTask;
use app\common\task\impl\UserFollowTeacherTask;
use app\common\utils\DateTimeUtil;
use think\Db;
use think\Exception;
use think\Log;
use think\Model;

/**
 * Class CreditRecord
 * @package app\common\model
 *
 * @property integer id
 * @property integer uid
 * @property integer change_type
 * @property integer amount
 * @property string remark
 * @property string ext
 * @property string created
 *
 */
class UserCreditRecord extends Model
{
    protected $table = 'user_credit_record';
    protected $pk = 'id';
    protected $field = [
        'uid',
        'change_type',
        'amount',
        'remark',
        'ext',
        'created',
    ];

    // 积分变更类型
    const CHANGE_TYPE_EXCHANGE          = -1;
    const CHANGE_TYPE_ASK               = -2;
    const CHANGE_TYPE_ASK_VIEW          = -3;

    const CHANGE_TYPE_REGISTER          = 1;
    const CHANGE_TYPE_ATTENDANCE        = 2;
    const CHANGE_TYPE_REAL_NAME         = 3;
    const CHANGE_TYPE_IMPROVE_MATERIAL  = 4;
    const CHANGE_TYPE_FOLLOWED_TEACHER  = 5;
    const CHANGE_TYPE_INVITE_USER       = 6;
    const CHANGE_TYPE_BUY_REBATE        = 7;
    const CHANGE_TYPE_INVITE_BUY_REBATE = 8;
    const CHANGE_TYPE_ASK_TIMEOUT_REFUND = 9;
    // 名称
    public static $ChangeTypeNames = [
        self::CHANGE_TYPE_EXCHANGE          => '兑换消费',
        self::CHANGE_TYPE_ASK               => '付费问答',
        self::CHANGE_TYPE_ASK_VIEW          => '问答答案偷看',

        self::CHANGE_TYPE_REGISTER          => '注册积分',
        self::CHANGE_TYPE_ATTENDANCE        => '每日签到',
        self::CHANGE_TYPE_REAL_NAME         => '实名认证',
        self::CHANGE_TYPE_IMPROVE_MATERIAL  => '完善资料',
        self::CHANGE_TYPE_FOLLOWED_TEACHER  => '关注',
        self::CHANGE_TYPE_INVITE_USER       => '邀请注册',
        self::CHANGE_TYPE_BUY_REBATE        => '消费获得积分',
        self::CHANGE_TYPE_INVITE_BUY_REBATE => '下线消费返积分',
        self::CHANGE_TYPE_ASK_TIMEOUT_REFUND => '付费问答超时积分返还',
    ];
    // 活动
    private static $TaskConfigurations = [
        self::CHANGE_TYPE_REGISTER          => [
            'name'      => '注册',
            'amount'    => 20,
            'class'     => DefaultOnceTask::class,
        ],
        self::CHANGE_TYPE_ATTENDANCE        => [
            'name'      => '每日签到',
            'amount'    => 5,
            'class'     => AttendanceTask::class,
       ],
        self::CHANGE_TYPE_REAL_NAME         => [
            'name'      => '实名认证',
            'amount'    => 20,
            'class'     => DefaultOnceTask::class,
        ],
        self::CHANGE_TYPE_IMPROVE_MATERIAL  => [
            'name'      => '完善资料',
            'amount'    => 20,
            'class'     => DefaultOnceTask::class,
        ],
        self::CHANGE_TYPE_FOLLOWED_TEACHER  => [
            'name'      => '关注',
            'amount'    => 5,
            'class'     => UserFollowTeacherTask::class,
            'maxTimes'  => 2, // 每日限制次数
        ],
        self::CHANGE_TYPE_INVITE_USER       => [
            'name'      => '邀请注册',
            'amount'    => 40,
            'class'     => InfiniteTask::class,
        ],
        self::CHANGE_TYPE_BUY_REBATE        => [
            'name'      => '消费获得积分',
            'percent'   => 0.5,
            'class'     => DefaultRebateTask::class,
        ],
        self::CHANGE_TYPE_INVITE_BUY_REBATE => [
            'name'      => '下线消费返积分',
            'percent'   => 0.1,
            'class'     => DefaultRebateTask::class,
        ],
    ];
    public static function configSet($json) {
        $configs = json_decode($json, true);
        foreach (self::$TaskConfigurations as $type => & $configuration) {
            $conf = $configs[$type] ?? null;
            if ($conf) {
                foreach ($conf as $key => $val) {
                    $configuration[$key] = $val;
                }
            }
        }
    }

    /**
     * 获取任务对象
     *
     * @param integer $type
     * @param integer $uid
     * @param mixed $params
     * @return ICreditTask
     * @throws Exception
     */
    public static function getTaskBean($type, $uid, $params = null) : ICreditTask {
        if (!isset(self::$TaskConfigurations[$type])) {
            throw new Exception('任务不存在', 1);
        }
        $conf = self::$TaskConfigurations[$type];
        if (isset($conf['bean']) == false) {
            $conf['type'] = $type;
            $conf['uid'] = $uid;
            $class = $conf['class'];
            $bean = new $class($conf);
            $bean->setParams($params);
            $conf['bean'] = $bean;
        }

        return $conf['bean'];
    }

    /**
     * 获取用户任务状态
     *
     * @param $uid
     * @param array $types
     * @return array
     */
    public static function getUserTasks($uid, ...$types) {
        $filter = count($types) > 0;
        $uts = [];
        foreach (self::$TaskConfigurations as $type => $config) {
            if ($filter && in_array($type, $types) === false) continue;
            $task = self::getTaskBean($type, $uid);
            if (isset($task['amount'])) {
                $desc = "{$task['name']}+{$task['amount']}积分";
            } elseif (isset($task['percent'])) {
                $percent = intval($task['percent']*100);
                $desc = "{$task['name']}返{$percent}%积分";
            } else {
                $desc = '';
            }
            $ut = [
                'type' => $type,
                'name' => $task['name'],
                'desc' => $task['desc'] ?? $desc,
                'finish' => $task->finished(),
            ];
            if (isset($task['maxTimes'])) {
                $ut['maxTimes'] = $task['maxTimes'];
                $ut['times'] = $task['times'];
            }
            $uts[] = $ut;
        }
        return $uts;
    }

    /**
     * 积分变动的记录
     *
     * @param int $uid
     * @param int $type
     * @param int $amount
     * @param string $remark
     * @param array|null $ext
     */
    public static function record($uid, $type, $amount, $remark, $ext = null) {
        $data = [
            'uid' => $uid,
            'change_type' => $type,
            'amount' => $amount,
            'remark' => $remark,
        ];
        if ($ext) {
            $data['ext'] = json_encode($ext);
        }

        self::create($data);
    }

    /**
     * 积分记录列表
     *
     * @param $uid
     * @param $rows
     * @param $page
     * @param bool $totalPage
     * @return mixed
     */
    public static function listUserRecord($uid, $rows, $page, $totalPage = false) {
        $q = Db::table('user_credit_record');
        $q->where('uid','=', $uid);
        $q->where('amount','<>','0');
        $q->order('id','desc');
        $q->field('id,change_type,amount,remark,created');
        $p = $q->paginate($rows,!$totalPage,['page'=>$page]);

        $re['list'] = $p->items();

        foreach ($re['list'] as & $item) {
            $item['created'] = DateTimeUtil::format($item['created']);
        }

        if ($totalPage) {
            $re['total'] = $p->total();
            $re['lastPage'] = $p->lastPage();
        }

        return $re;
    }

    /**
     * 统计积分
     *
     * @param $uid
     * @return mixed
     */
    public static function userStatistics($uid) {
        $sql = <<<SQL
SELECT
  sum(CASE WHEN change_type > 0
    THEN amount
      ELSE 0 END) got,
  sum(CASE WHEN change_type < 0
    THEN amount
      ELSE 0 END) use
FROM user_credit_record
WHERE uid = :uid
SQL;
        $re = Db::query($sql, ['uid' => $uid]);
        $re = $re[0];

        $re['use'] = abs($re['use']);

        return $re;
    }

    /**
     * 检查一次性记录
     *
     * @param $type
     * @param $uid
     * @return bool
     */
    public static function checkOnce($type, $uid) {
        $sql = <<<SQL
SELECT exists(
  SELECT 1 FROM user_credit_record WHERE uid=:uid AND change_type=:ct LIMIT 1
) e
SQL;
        $re = Db::query($sql, ['ct' => $type, 'uid' => $uid]);
        return $re[0]['e'] ?? false;
    }

    /**
     * 检查当天记录
     *
     * @param $type
     * @param $uid
     * @param $date
     * @return bool
     */
    public static function checkByDate($type, $uid, $date) {
        $sql = <<<SQL
SELECT exists(
  SELECT 1 FROM user_credit_record WHERE uid=:uid AND change_type=:ct AND created>:today LIMIT 1
) e
SQL;
        $re = Db::query($sql, ['ct' => $type, 'uid' => $uid, 'today' => $date]);
        return $re[0]['e'] ?? false;
    }

    /**
     * 统计当天记录数
     *
     * @param $type
     * @param $uid
     * @param $date
     * @return int
     */
    public static function countByDate($type, $uid, $date) {
        $sql = <<<SQL
SELECT count(*) c FROM user_credit_record WHERE uid=:uid AND change_type=:ct AND created BETWEEN :day_start AND :day_end
SQL;
        $day_start = $date;
        $day_end = date('Y-m-d', strtotime($date.' +1 day'));
        $re = Db::query($sql, ['ct' => $type, 'uid' => $uid, 'day_start'=>$day_start,'day_end'=>$day_end]);

        return $re[0]['c'] ?? 0;
    }

}